#pragma once
#include <functional>
#include <sys/socket.h>
#include <arpa/inet.h>
#include "inet_addr.hpp"
#include "logger.hpp"
using namespace logger_module;
using func_t =std::function<void(int,const std::string&,InetAddr&)>;
const int defaultfd =-1;
class udp_server
{
public:
    udp_server(uint16_t port,func_t func)
    :_port(port),
    _func(func),
    _sockfd(defaultfd),
    _isrunning(false)
    {

    }
    ~udp_server(){}
    void Init()
    {
        _sockfd=socket(AF_INET,SOCK_DGRAM,0);
        if(_sockfd<0)
        {
            LOG(log_level::FATAL)<<"sockfd get failure";
            exit(1);
        }
        LOG(log_level::INFO)<<"socket make success. sockfd: "<<_sockfd;
        struct sockaddr_in addr;
        addr.sin_family=AF_INET;
        addr.sin_port =htons(_port);
        addr.sin_addr.s_addr=INADDR_ANY;
        int n=bind(_sockfd, (struct sockaddr*)&addr,sizeof(addr));
        if(n!=0)
        {
        LOG(log_level::FATAL)<<"sockfd bind failure";
        exit(2);
        }
        LOG(log_level::INFO)<<"bind success";
    }
    void Start()
    {   
        _isrunning =true;
        while(_isrunning)
        {
        char buffer[128];
        struct sockaddr_in peer;
        socklen_t peerlen=sizeof(peer);
        int n=recvfrom(_sockfd,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&peer,&peerlen);
        if(n>0)
        {
            buffer[n]=0;
            // int peer_port=ntohs(peer.sin_port);
            // std::string peer_ip=inet_ntoa(peer.sin_addr);
            InetAddr client(peer);
            _func(_sockfd,buffer,client);
            // sendto(_sockfd,result.c_str(),result.size(),0,(struct sockaddr*)&peer,sizeof(peer));
        }
        else
        {
            LOG(log_level::ERROR)<<"recive failure";
        }
    }
    }
private:
    int _sockfd;
    uint16_t _port;
    func_t _func;
    bool _isrunning;
};